LayoutBuilder in Flutter – Detailed Notes
LayoutBuilder is an important Flutter widget used to create responsive and adaptive user interfaces. It provides the layout constraints available from its parent widget, allowing you to build different UI structures depending on the available width and height.
Unlike checking the physical device type, LayoutBuilder helps you make layout decisions based on the actual space available to a widget. This is especially useful for mobile, tablet, desktop, web, split-screen, and resizable applications.
1. What is LayoutBuilder?
LayoutBuilder is a Flutter widget that builds its child based on the constraints provided by its parent.
The builder callback receives two important values:
- BuildContext: Provides information about the widget's location in the widget tree.
- BoxConstraints: Describes the minimum and maximum width and height available to the widget.
Basic syntax:
LayoutBuilder(
builder: (context, constraints) {
return Widget();
},
)
The constraints object is an instance of BoxConstraints.
2. Why Use LayoutBuilder?
Modern Flutter applications can run on many different screen sizes. A UI that looks good on a phone may not be suitable for a tablet, desktop, or resizable browser window.
LayoutBuilder allows you to respond to the space actually available to a particular widget.
- Create responsive layouts.
- Switch between Row and Column layouts.
- Create mobile, tablet, and desktop layouts.
- Build responsive cards.
- Create adaptive dashboards.
- Control grid layouts.
- Prevent overflow.
- Create sidebar and detail layouts.
- Build reusable responsive components.
- Handle resizable Flutter Web and desktop windows.
3. Basic LayoutBuilder Example
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('LayoutBuilder Example'),
),
body: LayoutBuilder(
builder: (context, constraints) {
return Center(
child: Text(
'Available Width: ${constraints.maxWidth}',
),
);
},
),
),
);
}
}
Here, constraints.maxWidth represents the maximum width available to the LayoutBuilder.
4. Understanding BoxConstraints
LayoutBuilder provides a BoxConstraints object. It contains four major properties:
| Property |
Description |
minWidth |
Minimum width allowed. |
maxWidth |
Maximum width available. |
minHeight |
Minimum height allowed. |
maxHeight |
Maximum height available. |
Example:
LayoutBuilder(
builder: (context, constraints) {
print('Minimum Width: ${constraints.minWidth}');
print('Maximum Width: ${constraints.maxWidth}');
print('Minimum Height: ${constraints.minHeight}');
print('Maximum Height: ${constraints.maxHeight}');
return Container();
},
)
Flutter's layout system follows the general principle: constraints go down, sizes go up, and the parent sets the position.
5. LayoutBuilder and Available Width
The most common use of LayoutBuilder is checking constraints.maxWidth.
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return const Text('Small Layout');
}
return const Text('Large Layout');
},
)
This example creates one layout when the available width is below 600 logical pixels and another layout when the available width is 600 logical pixels or greater.
Important: 600 is only an example breakpoint. Breakpoints should be selected according to the requirements of your UI rather than assuming that every device belongs to a fixed category.
6. Responsive Mobile and Tablet Layout
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return const Column(
children: [
Text('Mobile Layout'),
Text('Menu'),
Text('Content'),
],
);
}
return const Row(
children: [
Expanded(
child: Text('Sidebar'),
),
Expanded(
flex: 2,
child: Text('Content'),
),
],
);
},
)
On a narrow area, the widgets are arranged vertically. On a wider area, they are arranged horizontally.
7. LayoutBuilder vs MediaQuery
Both LayoutBuilder and MediaQuery can be used for responsive layouts, but they provide different information.
| LayoutBuilder |
MediaQuery |
| Provides constraints from the parent. |
Provides information about the app window/view. |
| Works with the local available space. |
Useful for app-wide environmental information. |
Provides BoxConstraints. |
Provides Size and other MediaQuery information. |
| Excellent for reusable components. |
Useful when the entire app window size matters. |
| Useful for nested layouts. |
Useful for window size, padding, insets, accessibility and other view information. |
Example using MediaQuery:
final width = MediaQuery.sizeOf(context).width;
Example using LayoutBuilder:
LayoutBuilder(
builder: (context, constraints) {
final width = constraints.maxWidth;
return Text('Width: $width');
},
)
If you need the available space for a specific widget, LayoutBuilder is often the more appropriate choice.
8. LayoutBuilder Works with Local Constraints
One of the biggest advantages of LayoutBuilder is that it works with the constraints of its position in the widget tree.
Center(
child: SizedBox(
width: 500,
child: LayoutBuilder(
builder: (context, constraints) {
return Text(
'Maximum Width: ${constraints.maxWidth}',
);
},
),
),
)
Here, the LayoutBuilder is inside a widget that limits its width, so it can make layout decisions based on that local space rather than simply looking at the whole application window.
9. Creating a Responsive Row and Column
LayoutBuilder(
builder: (context, constraints) {
final isWide = constraints.maxWidth >= 700;
if (isWide) {
return Row(
children: [
Expanded(
child: Container(
padding: const EdgeInsets.all(20),
child: const Text('Left Content'),
),
),
Expanded(
child: Container(
padding: const EdgeInsets.all(20),
child: const Text('Right Content'),
),
),
],
);
}
return Column(
children: [
Container(
padding: const EdgeInsets.all(20),
child: const Text('Top Content'),
),
Container(
padding: const EdgeInsets.all(20),
child: const Text('Bottom Content'),
),
],
);
},
)
This pattern is useful for dashboards, profile pages, settings pages, product pages, and admin panels.
10. Creating Mobile, Tablet and Desktop Layouts
You can create multiple breakpoints based on available width.
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return const Text('Mobile');
} else if (constraints.maxWidth < 1000) {
return const Text('Tablet');
} else {
return const Text('Desktop');
}
},
)
A more complete example:
LayoutBuilder(
builder: (context, constraints) {
final width = constraints.maxWidth;
if (width < 600) {
return const MobileHome();
} else if (width < 1000) {
return const TabletHome();
} else {
return const DesktopHome();
}
},
)
This allows your application to provide different structures instead of simply stretching the same mobile layout across a very large screen.
11. Responsive Card Layout
LayoutBuilder(
builder: (context, constraints) {
final isWide = constraints.maxWidth > 700;
return isWide
? Row(
children: [
Expanded(child: _buildCard('Users')),
const SizedBox(width: 16),
Expanded(child: _buildCard('Orders')),
const SizedBox(width: 16),
Expanded(child: _buildCard('Revenue')),
],
)
: Column(
children: [
_buildCard('Users'),
const SizedBox(height: 16),
_buildCard('Orders'),
const SizedBox(height: 16),
_buildCard('Revenue'),
],
);
},
)
Widget _buildCard(String title) {
return Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Text(title),
),
);
}
12. Responsive Grid with LayoutBuilder
LayoutBuilder can also be used to determine how much space is available for a grid.
LayoutBuilder(
builder: (context, constraints) {
int columns;
if (constraints.maxWidth < 600) {
columns = 2;
} else if (constraints.maxWidth < 1000) {
columns = 3;
} else {
columns = 4;
}
return GridView.builder(
padding: const EdgeInsets.all(16),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
),
itemCount: 20,
itemBuilder: (context, index) {
return Card(
child: Center(
child: Text('Item ${index + 1}'),
),
);
},
);
},
)
For many responsive grids, another useful approach is SliverGridDelegateWithMaxCrossAxisExtent, which lets item width influence the number of columns instead of hard-coding a device-specific column count.
GridView.builder(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 250,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
),
itemCount: 30,
itemBuilder: (context, index) {
return Card(
child: Center(
child: Text('Product ${index + 1}'),
),
);
},
)
13. Responsive Sidebar and Content Layout
A common desktop pattern is to show a sidebar and content area side-by-side.
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 800) {
return Row(
children: [
const SizedBox(
width: 250,
child: ColoredBox(
color: Colors.black12,
child: Center(
child: Text('Sidebar'),
),
),
),
const VerticalDivider(width: 1),
const Expanded(
child: Center(
child: Text('Main Content'),
),
),
],
);
}
return const Center(
child: Text('Mobile Navigation'),
);
},
)
This pattern is useful for admin dashboards, email applications, contact applications, file managers and productivity tools.
14. Responsive Login Form
Forms often need a maximum width on tablets and desktop screens. A very wide form can reduce readability.
LayoutBuilder(
builder: (context, constraints) {
final formWidth = constraints.maxWidth > 500
? 400.0
: constraints.maxWidth * 0.9;
return Center(
child: SizedBox(
width: formWidth,
child: Column(
children: [
const TextField(
decoration: InputDecoration(
labelText: 'Email',
),
),
const SizedBox(height: 16),
const TextField(
obscureText: true,
decoration: InputDecoration(
labelText: 'Password',
),
),
const SizedBox(height: 20),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {},
child: const Text('Login'),
),
),
],
),
),
);
},
)
15. Using LayoutBuilder with Expanded
Expanded is useful when you want widgets to share the available space without using hard-coded widths.
LayoutBuilder(
builder: (context, constraints) {
return Row(
children: [
Expanded(
flex: 1,
child: Container(
height: 150,
child: const Center(
child: Text('25% Area'),
),
),
),
Expanded(
flex: 3,
child: Container(
height: 150,
child: const Center(
child: Text('75% Area'),
),
),
),
],
);
},
)
The available horizontal space is divided according to the flex values.
16. LayoutBuilder with ConstrainedBox
You can combine LayoutBuilder with ConstrainedBox to create a component that adapts while maintaining maximum and minimum dimensions.
LayoutBuilder(
builder: (context, constraints) {
return Center(
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 600,
),
child: const Padding(
padding: EdgeInsets.all(24),
child: Text(
'This content will not become excessively wide.',
),
),
),
);
},
)
17. Responsive Navigation
Navigation can change according to available space.
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return Scaffold(
bottomNavigationBar: NavigationBar(
destinations: const [
NavigationDestination(
icon: Icon(Icons.home),
label: 'Home',
),
NavigationDestination(
icon: Icon(Icons.person),
label: 'Profile',
),
],
),
body: const Center(
child: Text('Mobile Navigation'),
),
);
}
return Scaffold(
body: Row(
children: [
NavigationRail(
destinations: const [
NavigationRailDestination(
icon: Icon(Icons.home),
label: Text('Home'),
),
NavigationRailDestination(
icon: Icon(Icons.person),
label: Text('Profile'),
),
],
selectedIndex: 0,
onDestinationSelected: (index) {},
),
const Expanded(
child: Center(
child: Text('Large Screen Content'),
),
),
],
),
);
},
)
This allows a small window to use bottom navigation while a larger window uses a side navigation pattern.
18. Creating a Reusable ResponsiveBuilder
If the same responsive logic is required in multiple places, create a reusable widget.
class ResponsiveBuilder extends StatelessWidget {
final Widget Function(BuildContext context, BoxConstraints constraints)
builder;
const ResponsiveBuilder({
super.key,
required this.builder,
});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: builder,
);
}
}
Usage:
ResponsiveBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return const Text('Mobile');
}
return const Text('Large Screen');
},
)
19. Creating a Three-Breakpoint Responsive Widget
class ResponsiveLayout extends StatelessWidget {
const ResponsiveLayout({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return const MobileLayout();
}
if (constraints.maxWidth < 1000) {
return const TabletLayout();
}
return const DesktopLayout();
},
);
}
}
class MobileLayout extends StatelessWidget {
const MobileLayout({super.key});
@override
Widget build(BuildContext context) {
return const Center(
child: Text('Mobile Layout'),
);
}
}
class TabletLayout extends StatelessWidget {
const TabletLayout({super.key});
@override
Widget build(BuildContext context) {
return const Center(
child: Text('Tablet Layout'),
);
}
}
class DesktopLayout extends StatelessWidget {
const DesktopLayout({super.key});
@override
Widget build(BuildContext context) {
return const Center(
child: Text('Desktop Layout'),
);
}
}
20. LayoutBuilder Inside a Card
LayoutBuilder does not have to be placed at the root of your application. It can be placed inside individual components.
Card(
child: LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 300) {
return const Column(
children: [
Icon(Icons.person),
Text('User Profile'),
],
);
}
return const Row(
children: [
Icon(Icons.person),
SizedBox(width: 16),
Text('User Profile'),
],
);
},
),
)
This makes the component itself responsive and reusable in different parts of the application.
21. LayoutBuilder with ListView
LayoutBuilder can be useful when you need to understand the available space around a scrollable widget.
LayoutBuilder(
builder: (context, constraints) {
return ListView(
padding: const EdgeInsets.all(16),
children: [
Text(
'Available Width: ${constraints.maxWidth}',
),
const SizedBox(height: 20),
const Card(
child: Padding(
padding: EdgeInsets.all(20),
child: Text('Item 1'),
),
),
const Card(
child: Padding(
padding: EdgeInsets.all(20),
child: Text('Item 2'),
),
),
],
);
},
)
22. LayoutBuilder with SingleChildScrollView
A common pattern is to combine LayoutBuilder, SingleChildScrollView, and ConstrainedBox when content should fill the available area when possible but remain scrollable when it becomes larger.
LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text('Top'),
Text('Middle'),
Text('Bottom'),
],
),
),
);
},
)
This technique is useful for forms, login pages, onboarding screens and other vertically constrained layouts.
23. Understanding Tight and Loose Constraints
Flutter constraints can be tight or loose.
Tight Constraints
A tight constraint allows only one possible size. The minimum and maximum values are equal.
BoxConstraints.tight(
const Size(200, 100),
)
Loose Constraints
A loose constraint allows a widget to choose a size within an allowed range.
const BoxConstraints(
minWidth: 0,
maxWidth: 300,
)
Understanding constraints is important when working with LayoutBuilder, Row, Column, Expanded, Flexible, Center, ConstrainedBox and scrollable widgets.
24. LayoutBuilder and Overflow Prevention
Hard-coded widths can cause overflow on small screens.
Problematic example:
Row(
children: [
Container(width: 500, child: const Text('Content')),
Container(width: 500, child: const Text('Content')),
],
)
Better approach:
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 700) {
return const Column(
children: [
Text('Content 1'),
Text('Content 2'),
],
);
}
return const Row(
children: [
Expanded(child: Text('Content 1')),
Expanded(child: Text('Content 2')),
],
);
},
)
The layout changes structure instead of forcing two large widgets into a narrow area.
25. LayoutBuilder for Dashboard Design
LayoutBuilder(
builder: (context, constraints) {
final width = constraints.maxWidth;
if (width < 600) {
return const Column(
children: [
DashboardCard(title: 'Users'),
DashboardCard(title: 'Orders'),
DashboardCard(title: 'Revenue'),
],
);
}
if (width < 1000) {
return const GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
children: [
DashboardCard(title: 'Users'),
DashboardCard(title: 'Orders'),
DashboardCard(title: 'Revenue'),
DashboardCard(title: 'Pending'),
],
);
}
return const GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
),
children: [
DashboardCard(title: 'Users'),
DashboardCard(title: 'Orders'),
DashboardCard(title: 'Revenue'),
DashboardCard(title: 'Pending'),
],
);
},
)
class DashboardCard extends StatelessWidget {
final String title;
const DashboardCard({
super.key,
required this.title,
});
@override
Widget build(BuildContext context) {
return Card(
child: Center(
child: Text(title),
),
);
}
}
26. Complete Responsive LayoutBuilder Example
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: const ResponsiveHomePage(),
);
}
}
class ResponsiveHomePage extends StatelessWidget {
const ResponsiveHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Responsive Layout'),
),
body: LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return _buildMobile();
}
if (constraints.maxWidth < 1000) {
return _buildTablet();
}
return _buildDesktop();
},
),
);
}
Widget _buildMobile() {
return ListView(
padding: const EdgeInsets.all(16),
children: const [
Card(
child: Padding(
padding: EdgeInsets.all(20),
child: Text('Mobile Content'),
),
),
],
);
}
Widget _buildTablet() {
return GridView.count(
crossAxisCount: 2,
padding: const EdgeInsets.all(20),
crossAxisSpacing: 16,
mainAxisSpacing: 16,
children: const [
Card(child: Center(child: Text('Card 1'))),
Card(child: Center(child: Text('Card 2'))),
Card(child: Center(child: Text('Card 3'))),
Card(child: Center(child: Text('Card 4'))),
],
);
}
Widget _buildDesktop() {
return Row(
children: [
SizedBox(
width: 250,
child: Container(
color: Colors.black12,
child: const Center(
child: Text('Sidebar'),
),
),
),
const Expanded(
child: Center(
child: Text('Desktop Main Content'),
),
),
],
);
}
}
27. LayoutBuilder for List-Detail Interfaces
A list-detail layout is common in email, contacts and productivity applications.
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 700) {
return Row(
children: [
SizedBox(
width: 300,
child: ListView(
children: const [
ListTile(title: Text('Item 1')),
ListTile(title: Text('Item 2')),
ListTile(title: Text('Item 3')),
],
),
),
const VerticalDivider(width: 1),
const Expanded(
child: Center(
child: Text('Details'),
),
),
],
);
}
return ListView(
children: const [
ListTile(title: Text('Item 1')),
ListTile(title: Text('Item 2')),
ListTile(title: Text('Item 3')),
],
);
},
)
On large windows, the list and details can appear together. On smaller windows, the application can use navigation to move between them.
28. LayoutBuilder and Reusable Components
One of the best uses of LayoutBuilder is making individual widgets responsive.
class ResponsiveProductCard extends StatelessWidget {
const ResponsiveProductCard({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 250) {
return const Column(
children: [
Icon(Icons.shopping_bag, size: 50),
Text('Product'),
Text('₹999'),
],
);
}
return const Row(
children: [
Icon(Icons.shopping_bag, size: 50),
SizedBox(width: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Product'),
Text('₹999'),
],
),
],
);
},
);
}
}
29. Common Mistakes with LayoutBuilder
Mistake 1: Assuming LayoutBuilder Gives Device Information
LayoutBuilder does not tell you whether the device is a phone, tablet, or desktop. It provides constraints from the parent.
Mistake 2: Using Too Many Breakpoints
Creating many arbitrary breakpoints can make responsive logic complicated. Use breakpoints when the layout genuinely needs to change.
Mistake 3: Using Fixed Width Everywhere
Container(
width: 500,
)
This may not work well in a narrow layout.
Prefer flexible sizing where appropriate:
Expanded(
child: Container(),
)
Mistake 4: Ignoring Unbounded Constraints
Some widgets, especially scrollable widgets, can provide unbounded constraints in one direction. Understand the constraints before depending on maxWidth or maxHeight.
Mistake 5: Putting State Logic Inside Layout Decisions
Layout changes should describe the UI structure. Application state should still be managed explicitly using appropriate state-management techniques.
30. Best Practices for LayoutBuilder
- Use
LayoutBuilder when the local available space matters.
- Prefer available window or parent size over physical device type.
- Use meaningful breakpoints based on actual UI requirements.
- Use
Expanded and Flexible instead of unnecessary fixed widths.
- Use
ConstrainedBox or maximum widths to keep large-screen content readable.
- Test layouts at different window sizes.
- Design for split-screen and resizable windows.
- Keep responsive widgets reusable.
- Separate application data from presentation logic.
- Avoid making every widget independently dependent on global screen dimensions.
- Use
MediaQuery when you need app-window or environmental information and LayoutBuilder when you need local constraints.
31. LayoutBuilder vs Device-Based Checks
Avoid logic such as:
if (isTablet) {
// Tablet UI
}
A better approach is to ask how much space the application actually has:
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 700) {
return const LargeLayout();
}
return const SmallLayout();
},
)
This is more flexible because the same application can run in different window sizes, including split-screen and desktop/web environments.
32. LayoutBuilder Build Behavior
The builder callback receives the constraints needed to construct the layout. Flutter can avoid calling the builder again when the relevant constraints remain unchanged and the widget configuration has not changed.
Therefore, application state should not rely on an incidental rebuild of LayoutBuilder. When state changes, update state explicitly, normally with mechanisms such as setState for local state.
33. Practical Use Cases
| Use Case |
How LayoutBuilder Helps |
| Dashboard |
Changes cards between vertical, grid and wide layouts. |
| Login Form |
Controls form width and prevents excessive stretching. |
| Product Card |
Changes between Row and Column layouts. |
| Admin Panel |
Shows sidebar on wide screens. |
| Email App |
Displays list and details together when enough space exists. |
| Flutter Web |
Responds to browser window resizing. |
| Tablet UI |
Uses available space to create larger layouts. |
| Responsive Grid |
Adjusts the number or maximum width of grid items. |
| Forms |
Controls layout according to available width and height. |
34. LayoutBuilder and Flutter's Responsive Design Approach
Flutter's adaptive design guidance can be understood as three general steps:
- Abstract: Separate common data and UI concepts from the specific layout.
- Measure: Determine the available space using tools such as
MediaQuery or LayoutBuilder.
- Branch: Select an appropriate layout when the available space crosses a meaningful breakpoint.
This approach helps create interfaces that respond to the actual available space rather than relying on assumptions about a physical device.
35. Interview Questions
Q1. What is LayoutBuilder in Flutter?
Answer: LayoutBuilder is a widget that builds its child based on the constraints provided by its parent.
Q2. What does the builder callback receive?
Answer: It receives a BuildContext and a BoxConstraints object.
Q3. What is BoxConstraints?
Answer: BoxConstraints describes the minimum and maximum width and height available to a widget.
Q4. What is the difference between LayoutBuilder and MediaQuery?
Answer: LayoutBuilder provides local constraints from its parent, while MediaQuery provides information about the application window/view and other environmental properties.
Q5. Why is LayoutBuilder useful for responsive design?
Answer: It allows a widget to change its layout according to the actual space available to it.
Q6. Can LayoutBuilder detect whether a device is a phone or tablet?
Answer: No. It provides layout constraints. You should generally make layout decisions based on available space rather than physical device category.
Q7. What is constraints.maxWidth?
Answer: It represents the maximum width available to the widget from its parent constraints.
Q8. Can LayoutBuilder be nested?
Answer: Yes. Nested LayoutBuilders can respond to the constraints available at different locations in the widget tree.
Q9. Can LayoutBuilder be used inside a Card?
Answer: Yes. This is useful when a reusable component needs to change its internal layout based on the space allocated to it.
Q10. Is 600 pixels a universal Flutter breakpoint?
Answer: No. 600 logical pixels is a commonly used example in Flutter's adaptive-layout documentation, but breakpoints should be selected according to the requirements of the application's layout.
36. Practice Exercises
- Create a screen that displays a Column below 600 logical pixels and a Row above 600.
- Create a responsive login form with a maximum width of 400 pixels.
- Create a dashboard that displays one card per row on small screens and four cards on large screens.
- Create a product card that switches between Column and Row layouts.
- Create a responsive sidebar that appears only when enough horizontal space is available.
- Create a list-detail interface for mobile and desktop.
- Create a responsive navigation system using NavigationBar for small layouts and NavigationRail for larger layouts.
- Create a responsive grid using
SliverGridDelegateWithMaxCrossAxisExtent.
- Create a reusable
ResponsiveBuilder widget.
- Run the application in Flutter Web and resize the browser to observe layout changes.
37. Quick Revision
| Concept |
Key Point |
| LayoutBuilder |
Builds UI using parent constraints. |
| BoxConstraints |
Defines minimum and maximum width and height. |
| maxWidth |
Maximum available width. |
| maxHeight |
Maximum available height. |
| minWidth |
Minimum allowed width. |
| minHeight |
Minimum allowed height. |
| Responsive UI |
UI adapts to available space. |
| MediaQuery |
Provides app-window/view information and other environmental data. |
| Expanded |
Uses remaining available flex space. |
| Flexible |
Allows flexible sizing within a Flex layout. |
| ConstrainedBox |
Adds additional constraints. |
| Breakpoint |
A threshold at which the UI structure changes. |
38. Official Flutter Resources
39. Flutter Training Resources
For structured Flutter training and practical learning resources, visit:
JustAcademy Flutter Training Course
To register for a Flutter course demo:
Register for Flutter Course Demo
40. Conclusion
LayoutBuilder is one of the most useful Flutter widgets for building responsive and adaptive interfaces. It provides a BoxConstraints object containing the available minimum and maximum width and height, allowing components to respond to the space provided by their parent.
The key idea is to make layout decisions based on available space, not simply on whether the physical device is a phone, tablet, or desktop. By combining LayoutBuilder with BoxConstraints, Row, Column, Expanded, Flexible, ConstrainedBox, grids and navigation widgets, you can build Flutter applications that work effectively across different window sizes and platforms.